import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCA
from sklearn.manifold import Isomap, LocallyLinearEmbedding, SpectralEmbedding, TSNE

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def load_data(data_path):
    """加载MNIST数据集"""
    data = pd.read_csv(data_path)
    X = data.drop('label', axis=1).values
    y = data['label'].values
    # 数据归一化
    X = X / 255.0
    return X, y

def show_original_images(X, y, n_samples=10):
    """显示原始图像"""
    fig, axes = plt.subplots(2, 5, figsize=(12, 6))
    for i, ax in enumerate(axes.flat):
        idx = np.random.randint(0, X.shape[0])
        img = X[idx].reshape(28, 28)
        ax.imshow(img, cmap='gray')
        ax.set_title(f'标签: {y[idx]}')
        ax.axis('off')
    plt.tight_layout()
    plt.show()

def apply_pca(X):
    """应用PCA降维"""
    pca = PCA(n_components=2)
    X_pca = pca.fit_transform(X)
    return X_pca, pca.explained_variance_ratio_

def apply_isomap(X, n_samples=3000):
    """应用Isomap降维"""
    indices = np.random.choice(X.shape[0], n_samples, replace=False)
    X_sample = X[indices]
    isomap = Isomap(n_components=2, n_neighbors=10)
    X_isomap = isomap.fit_transform(X_sample)
    return X_isomap, indices

def apply_lle(X, n_samples=3000):
    """应用LLE降维"""
    indices = np.random.choice(X.shape[0], n_samples, replace=False)
    X_sample = X[indices]
    lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10)
    X_lle = lle.fit_transform(X_sample)
    return X_lle, indices

def apply_le(X, n_samples=3000):
    """应用LE（拉普拉斯特征映射）降维"""
    indices = np.random.choice(X.shape[0], n_samples, replace=False)
    X_sample = X[indices]
    le = SpectralEmbedding(n_components=2, n_neighbors=10)
    X_le = le.fit_transform(X_sample)
    return X_le, indices

def apply_tsne(X, n_samples=3000):
    """应用t-SNE降维"""
    indices = np.random.choice(X.shape[0], n_samples, replace=False)
    X_sample = X[indices]
    tsne = TSNE(n_components=2, random_state=42)
    X_tsne = tsne.fit_transform(X_sample)
    return X_tsne, indices

def plot_embedding(X_embedded, y, title):
    """绘制降维结果"""
    plt.figure(figsize=(10, 8))
    scatter = plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap='tab10')
    plt.colorbar(scatter)
    plt.title(title)
    plt.xlabel('第一维')
    plt.ylabel('第二维')
    plt.show()

def main():
    # 加载数据
    X, y = load_data('./exp4/src/train.csv')
    print('数据集形状:', X.shape)
    print('标签数量:', len(y))
    print('标签类别:', np.unique(y))

    # 显示原始图像
    show_original_images(X, y)

    # PCA降维
    X_pca, explained_variance = apply_pca(X)
    plot_embedding(X_pca, y, 'PCA降维结果')
    print('PCA解释方差比:', explained_variance)

    # 对其他方法使用采样数据
    # Isomap
    X_isomap, indices = apply_isomap(X)
    plot_embedding(X_isomap, y[indices], 'Isomap降维结果')

    # LLE
    X_lle, indices = apply_lle(X)
    plot_embedding(X_lle, y[indices], 'LLE降维结果')

    # LE
    X_le, indices = apply_le(X)
    plot_embedding(X_le, y[indices], 'LE降维结果')

    # t-SNE
    X_tsne, indices = apply_tsne(X)
    plot_embedding(X_tsne, y[indices], 't-SNE降维结果')

if __name__ == '__main__':
    main()